package com.netease.nim.demo.main.activity;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.netease.nim.demo.common.ui.imageview.HeadImageView;
import com.netease.nim.demo.main.reminder.SoundPlayer;
import com.netease.nimlib.sdk.NIMClient;
import com.netease.nimlib.sdk.Observer;
import com.netease.nimlib.sdk.RequestCallback;
import com.netease.nimlib.sdk.auth.ClientType;
import com.netease.nimlib.sdk.avchat.AVChatCallback;
import com.netease.nimlib.sdk.avchat.AVChatManager;
import com.netease.nimlib.sdk.avchat.AVChatStateObserver;
import com.netease.nimlib.sdk.avchat.constant.AVChatEventType;
import com.netease.nimlib.sdk.avchat.constant.AVChatTimeOutEvent;
import com.netease.nimlib.sdk.avchat.constant.AVChatType;
import com.netease.nimlib.sdk.avchat.constant.AVChatVideoScalingType;
import com.netease.nimlib.sdk.avchat.model.AVChatAudioFrame;
import com.netease.nimlib.sdk.avchat.model.AVChatCalleeAckEvent;
import com.netease.nimlib.sdk.avchat.model.AVChatCommonEvent;
import com.netease.nimlib.sdk.avchat.model.AVChatControlEvent;
import com.netease.nimlib.sdk.avchat.model.AVChatData;
import com.netease.nimlib.sdk.avchat.model.AVChatOnlineAckEvent;
import com.netease.nimlib.sdk.avchat.model.AVChatOptionalConfig;
import com.netease.nimlib.sdk.avchat.model.AVChatVideoFrame;
import com.netease.nimlib.sdk.avchat.model.AVChatVideoRender;
import com.netease.nimlib.sdk.uinfo.UserService;
import com.netease.nimlib.sdk.uinfo.model.NimUserInfo;
import com.netease.nrtc.sdk.NRtcConstants;
import com.shwread.android.qysw10000241.R;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import logic.constants.DefaultConsts;
import logic.util.NetworkUtil;

/**
 * 双人音视频通话界面
 */
public class NimAVChatActivity
        extends
        AppCompatActivity
        implements
        AVChatStateObserver,
        View.OnClickListener {

    private static final String TAG = "AVChat";

    //控制UI的显示
    private int viewType = TYPE_AUDIO_TO_VIDEO_REQUEST;
    private static final int TYPE_CALLED = 0;
    private static final int TYPE_VIDEO_CALL = TYPE_CALLED + 1;
    private static final int TYPE_VIDEO_NORMAL = TYPE_VIDEO_CALL + 1;
    private static final int TYPE_AUDIO_CALL = TYPE_VIDEO_NORMAL + 1;
    private static final int TYPE_AUDIO_NORMAL = TYPE_AUDIO_CALL + 1;
    private static final int TYPE_AUDIO_TO_VIDEO_REQUESTED = TYPE_AUDIO_NORMAL + 1;
    private static final int TYPE_AUDIO_TO_VIDEO_REQUEST = TYPE_AUDIO_TO_VIDEO_REQUESTED + 1;

    private boolean videoMode = false;          //是否是视频模式
    private boolean otherCameraOpened = true;   //对方摄像头是否开启
    private boolean selfSurfaceIsLarge = false; //当前用户的视频画面是大还是小
    private boolean selfThreadRunning = false;  //线程是否运行过
    private boolean remoteThreadRunning = false;//线程是否运行过
    private boolean leaved = false;             //防止多次toast

    //用户传递参数
    private String selfAccount;      //当前用户
    private String remoteAccount;    //对方用户
    private int type;                //通话类型 语音/视频
    private boolean call;            //true=主叫, false=被叫

    private AVChatOptionalConfig videoChatParam;
    private AVChatVideoRender remoteRender;
    private AVChatVideoRender selfRender;

    //layout
    private TextView tvChangeMode;
    private Chronometer videoTime;
    private LinearLayout smallPreview;//小视频窗口
    private LinearLayout largePreview;//主视频窗口
    private TextView tvStatus;
    //顶部头像、名称等
    private LinearLayout llTop;
    private HeadImageView ivHead;
    private TextView tvName;
    private Chronometer audioTime;
    private TextView tvRequestStatus;
    private TextView tvNotWifiTip;
    private TextView tvNetworkStatus;
    //底部视频工具栏
    private LinearLayout llVideoBottom;
    private TextView tvVideoRecording;
    private ImageButton ibChangeCamera;
    private ImageButton ibMuteVideo;
    private ImageButton ibMuteAudio;
    private ImageButton ibRecord;
    private ImageButton ibStop;
    //底部拒绝和接受按钮
    private LinearLayout llBottomButtons;
    private Button btnCancel;
    private Button btnOK;
    //底部语音工具栏
    private LinearLayout llAudioBottom;
    private TextView tvAudioRecording;
    private Button btnMuteAudio;
    private Button btnOpenSpeaker;
    private Button btnRecord;
    private Button btnStop;

    /**
     * 接收用户异常登录的广播
     */
    private LoginReceiver receiver;

    public static void launch(Context context, String selfAccount, String remoteAccount, int type, boolean call) {
        Intent intent = new Intent();
        intent.setClass(context, NimAVChatActivity.class);
        intent.putExtra("selfAccount", selfAccount);
        intent.putExtra("remoteAccount", remoteAccount);
        intent.putExtra("type", type);
        intent.putExtra("call", call);
        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

    private void setScreenOnFlag() {
        final int keepScreenOnFlag = WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
        Window w = getWindow();
        w.getAttributes().flags |= keepScreenOnFlag;
        w.addFlags(keepScreenOnFlag);
    }

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case RESULT_OK:
                    changeView(viewType);
                    break;
            }
        }
    };

    private class LoginReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context arg0, Intent arg1) {
            final String json = arg1.getStringExtra("json");
            if (!TextUtils.isEmpty(json) && "1003".equals(json)) {
                AVChatManager.getInstance().hangUp(null);//挂断
                leave("");
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        registerObserve(false);
    }

    @Override
    public void onBackPressed() {
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setScreenOnFlag();
        setContentView(R.layout.nim_avchat_activity);
        remoteRender = new AVChatVideoRender(this);
        selfRender = new AVChatVideoRender(this);

        configFromIntent(getIntent());
        initView();
        initData();
        setListener();

        videoMode = (type == AVChatType.VIDEO.getValue());
        videoChatParam = new AVChatOptionalConfig();
        videoChatParam.enableCallProximity(false)//通话距离感应
                .enableVideoCrop(true)//视频裁剪
                .enableVideoRotate(true)//视频旋转
                .enableServerRecordAudio(true)//服务器录制音频
                .enableServerRecordVideo(true)//服务器录制视频
                .setVideoQuality(NRtcConstants.VideoQuality.QUALITY_480P)//发送期望视频码率
                .enableVideoFpsReported(false);//设置是否允许视频帧率汇报
        if (call) {
            if (!videoMode) {
                viewType = TYPE_AUDIO_CALL;
            } else {
                viewType = TYPE_VIDEO_CALL;
            }
            //发起通话
            AVChatManager.getInstance().call(remoteAccount,
                    videoMode ? AVChatType.VIDEO : AVChatType.AUDIO,
                    videoMode ? videoChatParam : null,
                    null, new AVChatCallback<AVChatData>() {
                        @Override
                        public void onSuccess(AVChatData avChatData) {
                            //监听被叫方回应
                            Log.i(TAG, "发起通话成功");
                            AVChatManager.getInstance().observeCalleeAckNotification(callAckObserver, true);
                        }

                        /**
                         * 注意：由于音视频引擎析构需要时间，请尽可能保证上一次通话挂断到本次电话接听时间间隔
                         * 在2秒以上，否则有可能在接听时出现初始化引擎失败（code = -1）
                         */
                        @Override
                        public void onFailed(int code) {
                            switch (code) {
                                case -1:
                                    leave("初始化引擎失败");
                                    break;
                                case 9102:
                                    leave("通道失效");
                                    break;
                                case 9103:
                                    leave("已被其他端响应");
                                    break;
                                case 11001:
                                    leave("对方不在线");
                                    break;
                                case 403:
                                    leave("暂无权限，请开通音视频服务");
                                    break;
                            }
                        }

                        @Override
                        public void onException(Throwable throwable) {
                            throwable.printStackTrace();
                        }
                    });
        } else {
            viewType = TYPE_CALLED;
        }
        changeView(viewType);
        registerObserve(true);
    }

    private void registerObserve(boolean register) {
        //监听对方挂断
        AVChatManager.getInstance().observeHangUpNotification(callHangupObserver, register);
        //双方通话建立之后，需要监听通话控制通知
        AVChatManager.getInstance().observeControlNotification(callControlObserver, register);
        //主叫方在拨打网络通话时，超过45秒被叫方还未接听来电，则自动挂断。被叫方超过45秒未接听来听，也会自动挂断，在通话过程中网络超时30秒自动挂断
        AVChatManager.getInstance().observeTimeoutNotification(timeoutObserver, register);
        //网络通话发起或者正在接通时，需要监听是否有本地来电（用户接通本地来电）。若有本地来电，网络通话自动拒绝或者挂断
        AVChatManager.getInstance().observeAutoHangUpForLocalPhone(autoHangUpForLocalPhoneObserver, register);
        //监听该帐号其他端回应（被叫方）
        AVChatManager.getInstance().observeOnlineAckNotification(onlineAckObserver, register);
        //监听通话过程中状态变化
        AVChatManager.getInstance().observeAVChatState(this, register);
        //抢登监听
        if (register) {
            receiver = new LoginReceiver();
            registerReceiver(receiver, new IntentFilter(DefaultConsts.EXCEPTION_LOGIN_STRING));
        } else {
            unregisterReceiver(receiver);
        }
    }

    /**
     * 拨号回应监听
     */
    Observer<AVChatCalleeAckEvent> callAckObserver = new Observer<AVChatCalleeAckEvent>() {
        @Override
        public void onEvent(AVChatCalleeAckEvent ackInfo) {
            SoundPlayer.instance(NimAVChatActivity.this).stop();
            if (ackInfo.getEvent() == AVChatEventType.CALLEE_ACK_BUSY) {//对方正在忙
                SoundPlayer.instance(NimAVChatActivity.this).play(SoundPlayer.RingerTypeEnum.PEER_BUSY);
                leave("对方正在忙");
            } else if (ackInfo.getEvent() == AVChatEventType.CALLEE_ACK_REJECT) {//对方拒绝接听
                leave("对方拒绝接听");
            } else if (ackInfo.getEvent() == AVChatEventType.CALLEE_ACK_AGREE) {//对方同意接听
                if (ackInfo.isDeviceReady()) {//设备初始化成功，开始通话
                    if (videoMode) {
                        viewType = TYPE_VIDEO_NORMAL;
                        initCamera();
                    } else {
                        viewType = TYPE_AUDIO_NORMAL;
                        changeView(viewType);
                    }
                    audioTime.start();
                    videoTime.start();
                } else {
                    AVChatManager.getInstance().hangUp(null);//挂断
                    //设备初始化失败，无法进行通话
                    leave("设备初始化失败，无法进行通话");
                }
            }
        }
    };

    Observer<AVChatCommonEvent> callHangupObserver = new Observer<AVChatCommonEvent>() {
        @Override
        public void onEvent(AVChatCommonEvent hangUpInfo) {
            //结束通话
            leave("对方已挂断");
        }
    };

    Observer<AVChatControlEvent> callControlObserver = new Observer<AVChatControlEvent>() {
        @Override
        public void onEvent(AVChatControlEvent event) {
            switch (event.getControlCommand()) {
                case SWITCH_AUDIO_TO_VIDEO://对方请求切换音频到视频
                    viewType = TYPE_AUDIO_TO_VIDEO_REQUESTED;
                    changeView(viewType);
                    break;
                case SWITCH_AUDIO_TO_VIDEO_AGREE://对方同意切换音频到视频
                    videoMode = true;
                    viewType = TYPE_VIDEO_NORMAL;
                    changeView(viewType);
                    break;
                case SWITCH_AUDIO_TO_VIDEO_REJECT://对方拒绝切换音频到视频
                    viewType = TYPE_AUDIO_NORMAL;
                    changeView(viewType);
                    Toast.makeText(NimAVChatActivity.this, "对方拒绝切换到视频", Toast.LENGTH_SHORT).show();
                    break;
                case SWITCH_VIDEO_TO_AUDIO://对方请求视频切换到音频
                    videoMode = false;
                    viewType = TYPE_AUDIO_NORMAL;
                    changeView(viewType);
                    break;
                case NOTIFY_VIDEO_OFF: //对方关闭视频的通知
                    otherCameraOpened = false;
                    viewType = TYPE_VIDEO_NORMAL;
                    changeView(viewType);
                    break;
                case NOTIFY_VIDEO_ON://对方开启视频的通知
                    otherCameraOpened = true;
                    viewType = TYPE_VIDEO_NORMAL;
                    changeView(viewType);
                    break;
            }
        }
    };

    Observer<AVChatTimeOutEvent> timeoutObserver = new Observer<AVChatTimeOutEvent>() {
        @Override
        public void onEvent(AVChatTimeOutEvent event) {
            //超时类型
            leave("连接超时");
        }
    };

    /**
     * 参数为自动挂断的原因：
     * 1 作为被叫方：网络通话有来电还未接通，此时有本地来电，那么拒绝网络来电
     * 2 作为主叫方：正在发起网络通话时有本地来电，那么挂断网络呼叫
     * 3 双方正在进行网络通话，当有本地来电，用户接听时，挂断网络通话
     * 4 如果发起网络通话，无论是否建立连接，用户又拨打本地电话，那么网络通话挂断
     */
    Observer<Integer> autoHangUpForLocalPhoneObserver = new Observer<Integer>() {
        @Override
        public void onEvent(Integer integer) {
            //结束通话
            leave("");
        }
    };

    /**
     * 如果自己的帐号有其他端在线（PC、Web），来电会被其他端做了回应，那么移动端会收到一条通知。因此，移动端在收到来电后需要监听 PC 端对主叫方的响应。
     */
    Observer<AVChatOnlineAckEvent> onlineAckObserver = new Observer<AVChatOnlineAckEvent>() {
        @Override
        public void onEvent(AVChatOnlineAckEvent ackInfo) {
            if (ackInfo.getClientType() != ClientType.Android) {
                switch (ackInfo.getClientType()) {
                    case ClientType.Windows:
                        leave("已被电脑端接听");
                        break;
                    case ClientType.iOS:
                        leave("已被IOS端接听");
                        break;
                    case ClientType.Web:
                        leave("已被网页端接听");
                        break;
                    case ClientType.WP:
                        leave("已被WP端接听");
                        break;
                }
            }
        }
    };

    /**
     * 获取上个界面传递过来的值
     */
    private void configFromIntent(Intent intent) {
        selfAccount = intent.getStringExtra("selfAccount");
        remoteAccount = intent.getStringExtra("remoteAccount");
        type = intent.getIntExtra("type", 0);
        call = intent.getBooleanExtra("call", true);
    }

    private void initView() {
        tvChangeMode = (TextView) findViewById(R.id.tv_nim_avchat_change_mode);
        videoTime = (Chronometer) findViewById(R.id.cm_nim_avchat_video);
        smallPreview = (LinearLayout) findViewById(R.id.ll_nim_avchat_small_size_preview);
        largePreview = (LinearLayout) findViewById(R.id.ll_nim_avchat_large_size_preview);
        tvStatus = (TextView) findViewById(R.id.tv_nim_avchat_status);

        llTop = (LinearLayout) findViewById(R.id.ll_nim_avchat_top);
        ivHead = (HeadImageView) findViewById(R.id.iv_nim_avchat_head);
        tvName = (TextView) findViewById(R.id.tv_nim_avchat_name);
        audioTime = (Chronometer) findViewById(R.id.cm_nim_avchat_audio);
        tvRequestStatus = (TextView) findViewById(R.id.tv_nim_avchat_request_status);
        tvNotWifiTip = (TextView) findViewById(R.id.tv_nim_avchat_not_wifi_tip);
        tvNetworkStatus = (TextView) findViewById(R.id.tv_nim_avchat_network_status);

        tvVideoRecording = (TextView) findViewById(R.id.tv_nim_avchat_video_recording);
        llVideoBottom = (LinearLayout) findViewById(R.id.ll_nim_avchat_bottom_video);
        ibChangeCamera = (ImageButton) findViewById(R.id.ib_nim_avchat_change_camera);
        ibMuteVideo = (ImageButton) findViewById(R.id.ib_nim_avchat_mute_video);
        ibMuteAudio = (ImageButton) findViewById(R.id.ib_nim_avchat_mute_audio);
        ibRecord = (ImageButton) findViewById(R.id.ib_nim_avchat_record);
        ibStop = (ImageButton) findViewById(R.id.ib_nim_avchat_stop);

        llBottomButtons = (LinearLayout) findViewById(R.id.ll_nim_avchat_bottom_buttons);
        btnCancel = (Button) findViewById(R.id.btn_nim_avchat_cancel);
        btnOK = (Button) findViewById(R.id.btn_nim_avchat_ok);

        tvAudioRecording = (TextView) findViewById(R.id.tv_nim_avchat_audio_recording);
        llAudioBottom = (LinearLayout) findViewById(R.id.ll_nim_avchat_audio_bottom);
        btnMuteAudio = (Button) findViewById(R.id.btn_nim_avchat_mute_audio);
        btnOpenSpeaker = (Button) findViewById(R.id.btn_nim_avchat_open_speaker);
        btnRecord = (Button) findViewById(R.id.btn_nim_avchat_record);
        btnStop = (Button) findViewById(R.id.btn_nim_avchat_stop);
    }

    private void initData() {
        List<String> list = new ArrayList<>();
        list.add(remoteAccount);
        ivHead.loadBuddyHeadImage(remoteAccount);
        NIMClient.getService(UserService.class).fetchUserInfo(list).setCallback(new RequestCallback<List<NimUserInfo>>() {
            @Override
            public void onSuccess(List<NimUserInfo> nimUserInfos) {
                if (nimUserInfos != null && nimUserInfos.size() > 0)
                {
                    if (!TextUtils.isEmpty(nimUserInfos.get(0).getAvatar())) Glide.with(NimAVChatActivity.this).load(nimUserInfos.get(0).getAvatar()).into(ivHead);
                    if (!TextUtils.isEmpty(nimUserInfos.get(0).getName())) tvName.setText(nimUserInfos.get(0).getName());
                }
            }

            @Override
            public void onFailed(int i) {

            }

            @Override
            public void onException(Throwable throwable) {

            }
        });
    }

    private void setListener() {
        tvChangeMode.setOnClickListener(this);
        smallPreview.setOnClickListener(this);
        ibChangeCamera.setOnClickListener(this);
        ibMuteVideo.setOnClickListener(this);
        ibMuteAudio.setOnClickListener(this);
        ibRecord.setOnClickListener(this);
        ibStop.setOnClickListener(this);
        btnCancel.setOnClickListener(this);
        btnOK.setOnClickListener(this);
        btnMuteAudio.setOnClickListener(this);
        btnOpenSpeaker.setOnClickListener(this);
        btnRecord.setOnClickListener(this);
        btnStop.setOnClickListener(this);
    }

    //修改页面显示内容
    private void changeView(int type) {
        switch (type) {
            case TYPE_CALLED:
                SoundPlayer.instance(this).play(SoundPlayer.RingerTypeEnum.RING);
                tvChangeMode.setVisibility(View.INVISIBLE);
                videoTime.setVisibility(View.INVISIBLE);
                largePreview.setVisibility(View.GONE);
                smallPreview.setVisibility(View.GONE);
                tvStatus.setVisibility(View.GONE);
                llTop.setVisibility(View.VISIBLE);
                audioTime.setVisibility(View.GONE);
                tvRequestStatus.setVisibility(View.VISIBLE);
                tvRequestStatus.setText(getString(videoMode ? R.string.avchat_video_call_request : R.string.avchat_audio_call_request));
                tvNotWifiTip.setVisibility(View.GONE);
                tvNetworkStatus.setVisibility(View.GONE);
                llAudioBottom.setVisibility(View.GONE);
                llVideoBottom.setVisibility(View.GONE);
                llBottomButtons.setVisibility(View.VISIBLE);
                btnOK.setText(getString(R.string.avchat_pickup));
                break;
            case TYPE_VIDEO_CALL:
                SoundPlayer.instance(this).play(SoundPlayer.RingerTypeEnum.CONNECTING);
                tvChangeMode.setVisibility(View.INVISIBLE);
                videoTime.setVisibility(View.INVISIBLE);
                largePreview.setVisibility(View.GONE);
                smallPreview.setVisibility(View.GONE);
                tvStatus.setVisibility(View.GONE);
                llTop.setVisibility(View.VISIBLE);
                audioTime.setVisibility(View.GONE);
                tvRequestStatus.setVisibility(View.VISIBLE);
                tvRequestStatus.setText(getString(R.string.avchat_wait_receive));
                tvNotWifiTip.setVisibility(View.GONE);
                tvNetworkStatus.setVisibility(View.GONE);
                llAudioBottom.setVisibility(View.GONE);
                llVideoBottom.setVisibility(View.VISIBLE);
                llBottomButtons.setVisibility(View.GONE);
                ibChangeCamera.setEnabled(false);
                ibMuteVideo.setEnabled(false);
                ibMuteAudio.setEnabled(false);
                ibRecord.setEnabled(false);
                break;
            case TYPE_VIDEO_NORMAL:
                SoundPlayer.instance(this).stop();
                tvChangeMode.setText(getString(R.string.avchat_switch_to_audio));
                tvChangeMode.setCompoundDrawablesWithIntrinsicBounds(R.drawable.avchat_change_to_audio, 0, 0, 0);
                tvChangeMode.setVisibility(View.VISIBLE);
                videoTime.setVisibility(View.VISIBLE);
                largePreview.setVisibility(View.VISIBLE);
                smallPreview.setVisibility(View.VISIBLE);
                llTop.setVisibility(View.GONE);
                llAudioBottom.setVisibility(View.GONE);
                llVideoBottom.setVisibility(View.VISIBLE);
                llBottomButtons.setVisibility(View.GONE);
                if (AVChatManager.getInstance().hasMultipleCameras()) {//是否有多个摄像头
                    ibChangeCamera.setEnabled(true);
                }
                ibMuteVideo.setEnabled(true);
                ibMuteAudio.setEnabled(true);
                ibRecord.setEnabled(true);
//                if (!selfThreadRunning) {
//                    selfSurfaceRenderThread.start();
//                }
//                if (!remoteThreadRunning) {
//                    remoteSurfaceRenderThread.start();
//                }
                setCameraSelf();
                setCameraRemote();
                smallPreview.removeAllViews();
                largePreview.removeAllViews();
                selfRender.setZOrderMediaOverlay(!selfSurfaceIsLarge);
                selfRender.setZOrderOnTop(!selfSurfaceIsLarge);
                remoteRender.setZOrderMediaOverlay(selfSurfaceIsLarge);
                remoteRender.setZOrderOnTop(selfSurfaceIsLarge);
                if (selfSurfaceIsLarge) {//当前用户视频大窗口
                    if (!AVChatManager.getInstance().isLocalVideoMuted()) {
                        largePreview.addView(selfRender);
                        tvStatus.setVisibility(View.GONE);
                    } else {
                        tvStatus.setText(getString(R.string.avchat_local_close_camera));
                        tvStatus.setVisibility(View.VISIBLE);
                    }
                    if (otherCameraOpened) {
                        smallPreview.addView(remoteRender);
                    }
                } else {//当前用户视频小窗口
                    if (!AVChatManager.getInstance().isLocalVideoMuted()) {
                        smallPreview.addView(selfRender);
                    }
                    if (otherCameraOpened) {
                        largePreview.addView(remoteRender);
                        tvStatus.setVisibility(View.GONE);
                    } else {
                        tvStatus.setText(getString(R.string.avchat_peer_close_camera));
                        tvStatus.setVisibility(View.VISIBLE);
                    }
                }
                ibMuteVideo.setSelected(AVChatManager.getInstance().isLocalVideoMuted());
                tvVideoRecording.setVisibility(AVChatManager.getInstance().isLocalRecording() ? View.VISIBLE : View.GONE);
                tvAudioRecording.setVisibility(View.GONE);
                ibRecord.setSelected(AVChatManager.getInstance().isLocalRecording());
                break;
            case TYPE_AUDIO_CALL:
                SoundPlayer.instance(this).play(SoundPlayer.RingerTypeEnum.CONNECTING);
                tvChangeMode.setVisibility(View.INVISIBLE);
                videoTime.setVisibility(View.INVISIBLE);
                largePreview.setVisibility(View.GONE);
                smallPreview.setVisibility(View.GONE);
                tvStatus.setVisibility(View.GONE);
                llTop.setVisibility(View.VISIBLE);
                audioTime.setVisibility(View.GONE);
                tvRequestStatus.setVisibility(View.VISIBLE);
                tvRequestStatus.setText(getString(R.string.avchat_wait_receive));
                tvNotWifiTip.setVisibility(NetworkUtil.isWifi(this) ? View.GONE : View.VISIBLE);
                tvNetworkStatus.setVisibility(View.GONE);
                llAudioBottom.setVisibility(View.VISIBLE);
                llVideoBottom.setVisibility(View.GONE);
                llBottomButtons.setVisibility(View.GONE);
                btnRecord.setEnabled(false);
                break;
            case TYPE_AUDIO_NORMAL:
                SoundPlayer.instance(this).stop();
                tvChangeMode.setText(getString(R.string.avchat_switch_to_video));
                tvChangeMode.setCompoundDrawablesWithIntrinsicBounds(R.drawable.avchat_change_to_video, 0, 0, 0);
                tvChangeMode.setVisibility(View.VISIBLE);
                videoTime.setVisibility(View.INVISIBLE);
                largePreview.removeAllViews();
                smallPreview.removeAllViews();
                largePreview.setVisibility(View.GONE);
                smallPreview.setVisibility(View.GONE);
                tvStatus.setVisibility(View.GONE);
                llTop.setVisibility(View.VISIBLE);
                audioTime.setVisibility(View.VISIBLE);
                tvRequestStatus.setVisibility(View.GONE);
                tvNotWifiTip.setVisibility(View.GONE);
                tvNetworkStatus.setVisibility(View.VISIBLE);
                llAudioBottom.setVisibility(View.VISIBLE);
                llVideoBottom.setVisibility(View.GONE);
                llBottomButtons.setVisibility(View.GONE);
                btnRecord.setEnabled(true);
                tvVideoRecording.setVisibility(View.GONE);
                tvAudioRecording.setVisibility(AVChatManager.getInstance().isLocalRecording() ? View.VISIBLE : View.GONE);
                btnRecord.setSelected(AVChatManager.getInstance().isLocalRecording());
                break;
            case TYPE_AUDIO_TO_VIDEO_REQUESTED:
                tvChangeMode.setText(getString(R.string.avchat_switch_to_video));
                tvChangeMode.setCompoundDrawablesWithIntrinsicBounds(R.drawable.avchat_change_to_video, 0, 0, 0);
                tvChangeMode.setVisibility(View.VISIBLE);
                videoTime.setVisibility(View.INVISIBLE);
                largePreview.setVisibility(View.GONE);
                smallPreview.setVisibility(View.GONE);
                tvStatus.setVisibility(View.GONE);
                llTop.setVisibility(View.VISIBLE);
                audioTime.setVisibility(View.VISIBLE);
                tvRequestStatus.setVisibility(View.VISIBLE);
                tvRequestStatus.setText(getString(R.string.avchat_audio_to_video_invitation));
                tvNotWifiTip.setVisibility(View.GONE);
                tvNetworkStatus.setVisibility(View.VISIBLE);
                llAudioBottom.setVisibility(View.GONE);
                llVideoBottom.setVisibility(View.GONE);
                llBottomButtons.setVisibility(View.VISIBLE);
                btnOK.setText(getString(R.string.avchat_receive));
                break;
            case TYPE_AUDIO_TO_VIDEO_REQUEST:
                tvChangeMode.setText(getString(R.string.avchat_switch_to_audio));
                tvChangeMode.setCompoundDrawablesWithIntrinsicBounds(R.drawable.avchat_change_to_audio, 0, 0, 0);
                tvChangeMode.setVisibility(View.VISIBLE);
                videoTime.setVisibility(View.VISIBLE);
                largePreview.setVisibility(View.GONE);
                smallPreview.setVisibility(View.GONE);
                tvStatus.setVisibility(View.VISIBLE);
                tvStatus.setText(getString(R.string.avchat_audio_to_video_wait));
                llTop.setVisibility(View.GONE);
                llAudioBottom.setVisibility(View.GONE);
                llVideoBottom.setVisibility(View.VISIBLE);
                llBottomButtons.setVisibility(View.GONE);
                ibChangeCamera.setEnabled(false);
                ibMuteVideo.setEnabled(false);
                ibMuteAudio.setEnabled(false);
                ibRecord.setEnabled(false);
                break;
        }
    }

    private void leave(String tip) {
        if (leaved) {
            return;
        } else {
            leaved = true;
        }
        SoundPlayer.instance(this).stop();
        if (!TextUtils.isEmpty(tip)) {
            Toast.makeText(this, tip, Toast.LENGTH_SHORT).show();
        }
        if (AVChatManager.getInstance().isLocalRecording()) {
            //停止录制
            AVChatManager.getInstance().stopLocalRecord();
        }
        finish();
    }

    @Override
    public void onClick(final View v) {
        if (v == tvChangeMode) {
            if (viewType == TYPE_AUDIO_TO_VIDEO_REQUEST) {
                Toast.makeText(this, getString(R.string.avchat_in_switch), Toast.LENGTH_SHORT).show();
            } else if (viewType == TYPE_AUDIO_TO_VIDEO_REQUESTED) {
                //同意音频切换到视频
                AVChatManager.getInstance().ackSwitchToVideo(true, new AVChatCallback<Void>() {
                    @Override
                    public void onSuccess(Void aVoid) {
                        videoMode = true;
                        viewType = TYPE_VIDEO_NORMAL;
                        changeView(viewType);
                    }

                    @Override
                    public void onFailed(int code) {

                    }

                    @Override
                    public void onException(Throwable throwable) {

                    }
                });
            } else {
                if (tvChangeMode.getText().toString().equals(getString(R.string.avchat_switch_to_audio))) {
                    //请求视频切换到音频
                    AVChatManager.getInstance().requestSwitchToAudio(new AVChatCallback<Void>() {
                        @Override
                        public void onSuccess(Void aVoid) {
                            viewType = TYPE_AUDIO_NORMAL;
                            changeView(viewType);
                        }

                        @Override
                        public void onFailed(int code) {

                        }

                        @Override
                        public void onException(Throwable throwable) {

                        }
                    });
                } else {
                    //请求音频切换到视频，需要传入VideoChatParam
                    AVChatManager.getInstance().requestSwitchToVideo(new AVChatCallback<Void>() {
                        @Override
                        public void onSuccess(Void aVoid) {
                            viewType = TYPE_AUDIO_TO_VIDEO_REQUEST;
                            changeView(viewType);
                        }

                        @Override
                        public void onFailed(int code) {

                        }

                        @Override
                        public void onException(Throwable throwable) {

                        }
                    });
                }
            }
        } else if (v == smallPreview) {//小窗口点击切换
            switchRender();
        } else if (v == ibChangeCamera) {//切换摄像头
            AVChatManager.getInstance().switchCamera();
        } else if (v == ibMuteVideo) {//开关本地视频
            AVChatManager.getInstance().muteLocalVideo(!AVChatManager.getInstance().isLocalVideoMuted());
            viewType = TYPE_VIDEO_NORMAL;
            changeView(viewType);
        } else if (v == ibMuteAudio || v == btnMuteAudio) {//开关音频
            AVChatManager.getInstance().muteLocalAudio(!AVChatManager.getInstance().isLocalAudioMuted());
            ibMuteAudio.setSelected(AVChatManager.getInstance().isLocalAudioMuted());
            btnMuteAudio.setSelected(AVChatManager.getInstance().isLocalAudioMuted());
        } else if (v == ibRecord || v == btnRecord) {//录制
            if (!AVChatManager.getInstance().isLocalRecording()) {
                Toast.makeText(this, getString(R.string.avchat_self_only), Toast.LENGTH_SHORT).show();
                //开始录制
                AVChatManager.getInstance().startLocalRecord();
            } else {
                //停止录制
                AVChatManager.getInstance().stopLocalRecord();
            }
            changeView(viewType);
        } else if (v == ibStop || v == btnStop) {
            AVChatManager.getInstance().hangUp(null);//挂断
            leave("");
        } else if (v == btnCancel) {
            if (viewType == TYPE_CALLED) {
                AVChatManager.getInstance().hangUp(null);//挂断
                leave("");
            } else if (viewType == TYPE_AUDIO_TO_VIDEO_REQUESTED) {
                //拒绝音频切换到视频
                AVChatManager.getInstance().ackSwitchToVideo(false, null);
                viewType = TYPE_AUDIO_NORMAL;
                changeView(viewType);
            }
        } else if (v == btnOpenSpeaker) {//扬声器开关
            AVChatManager.getInstance().setSpeaker(!AVChatManager.getInstance().speakerEnabled());
            btnOpenSpeaker.setSelected(AVChatManager.getInstance().speakerEnabled());
        } else if (v == btnOK) {
            if (viewType == TYPE_CALLED) {//同意接听
                AVChatManager.getInstance().accept(videoMode ? videoChatParam : null, new AVChatCallback<Void>() {
                    @Override
                    public void onSuccess(Void aVoid) {
                        //设备初始化成功，开始通话
                        if (videoMode) {
                            viewType = TYPE_VIDEO_NORMAL;
                            initCamera();
                        } else {
                            viewType = TYPE_AUDIO_NORMAL;
                            changeView(viewType);
                        }
                        audioTime.start();
                        videoTime.start();
                    }

                    /**
                     * 注意：由于音视频引擎析构需要时间，请尽可能保证上一次通话挂断到本次电话接听时间间隔
                     * 在2秒以上，否则有可能在接听时出现初始化引擎失败（code = -1）
                     */
                    @Override
                    public void onFailed(int code) {

                    }

                    @Override
                    public void onException(Throwable throwable) {

                    }
                });
            } else if (viewType == TYPE_AUDIO_TO_VIDEO_REQUESTED) {
                //同意音频切换到视频
                AVChatManager.getInstance().ackSwitchToVideo(true, new AVChatCallback<Void>() {
                    @Override
                    public void onSuccess(Void aVoid) {
                        videoMode = true;
                        viewType = TYPE_VIDEO_NORMAL;
                        changeView(viewType);
                    }

                    @Override
                    public void onFailed(int code) {

                    }

                    @Override
                    public void onException(Throwable throwable) {

                    }
                });
            }
        }
    }

    /**
     * 截图回调
     */
    @Override
    public void onTakeSnapshotResult(String account, boolean success, String file) {
        Log.i(TAG, "onTakeSnapshotResult:success=" + success);
    }

    /**
     * 本地网络类型发生改变回调
     */
    @Override
    public void onConnectionTypeChanged(int current) {
        Log.w(TAG, "onConnectionTypeChanged");
    }

    /**
     * 本地音视频录制结束回调
     *
     * @param files 录制文件，由于不同的摄像头参数不一样可能会存在多个文件。
     * @param event 录制结束原因. 0,正常结束 1,异常结束(存储空间不足等)
     */
    @Override
    public void onLocalRecordEnd(String[] files, int event) {
        Log.i(TAG, "onLocalRecordEnd:event=" + event);
        if (files != null && files.length > 0) {
            Toast.makeText(this, getString(R.string.avchat_video_file_saved, files[0].substring(0, files[0].lastIndexOf("/"))), Toast.LENGTH_LONG).show();
        }
    }

    /**
     * 用户第一帧画面通知
     */
    @Override
    public void onFirstVideoFrameAvailable(String account) {
        Log.i(TAG, "onFirstVideoFrameAvailable");
    }

    /**
     * 用户视频帧率汇报
     */
    @Override
    public void onVideoFpsReported(String account, int fps) {
        Log.i(TAG, "onVideoFpsReported:fps=" + fps);
    }

    /**
     * 当前音视频服务器连接回调
     *
     * @param code 200 连接成功
     *             101 连接超时
     *             417 无效频道
     *             401 验证失败
     *             400 格式不对
     */
    @Override
    public void onJoinedChannel(int code, String filePath, String fileName) {
        Log.i(TAG, "onJoinedChannel:code=" + code);
    }

    @Override
    public void onLeaveChannel() {

    }

    /**
     * 加入当前音视频频道用户帐号回调
     */
    @Override
    public void onUserJoined(String account) {
        Log.i(TAG, "onUserJoin:account=" + account);
        if (videoMode/* && !remoteThreadRunning*/) {
//            remoteSurfaceRenderThread.start();
            setCameraRemote();
        }
    }

    /**
     * 当前用户离开频道回调
     *
     * @param event -1,用户超时离开 0,正常退出
     */
    @Override
    public void onUserLeave(String account, int event) {
        Log.w(TAG, "onUserLeave:account=" + account + ",event=" + event);
        //对方被抢登
        if (account.equals(remoteAccount)) {
            AVChatManager.getInstance().hangUp(null);//挂断
            leave("");
        }
    }

    /**
     * 版本协议不兼容回调
     *
     * @param status 0,自己版本过低 1,对方版本过低
     */
    @Override
    public void onProtocolIncompatible(int status) {
        Log.w(TAG, "onProtocolIncompatible:status=" + status);
        leave(status == 0 ? "当前版本过低" : "对方版本过低");
    }

    /**
     * 服务器断开回调
     */
    @Override
    public void onDisconnectServer() {
        Log.w(TAG, "onDisconnectServer");
        leave("服务器断开");
    }

    /**
     * 当前通话网络状况回调
     *
     * @param value value 0~3 ,the less the better; 0 : best; 3 : worst
     */
    @Override
    public void onNetworkQuality(String account, int value) {
        Log.w(TAG, "onNetworkStatusChange:value=" + value);
        int text = R.string.avchat_network_grade_0;
        int drawable = R.drawable.network_grade_0;
        switch (value) {
            case 0:
                text = R.string.avchat_network_grade_0;
                drawable = R.drawable.network_grade_0;
                break;
            case 1:
                text = R.string.avchat_network_grade_1;
                drawable = R.drawable.network_grade_1;
                break;
            case 2:
                text = R.string.avchat_network_grade_2;
                drawable = R.drawable.network_grade_2;
                break;
            case 3:
                text = R.string.avchat_network_grade_3;
                drawable = R.drawable.network_grade_3;
                break;
        }
        tvNetworkStatus.setText(getString(text));
        tvNetworkStatus.setCompoundDrawablesWithIntrinsicBounds(0, 0, drawable, 0);
    }

    /**
     * 音视频连接成功建立回调
     */
    @Override
    public void onCallEstablished() {
        Log.i(TAG, "onCallEstablished");
        if (videoMode/* && !selfThreadRunning*/) {
//            selfSurfaceRenderThread.start();
            setCameraSelf();
        }
    }

    /**
     * 音视频设备状态通知
     */
    @Override
    public void onDeviceEvent(int code, String desc) {
        Log.w(TAG, "onDeviceEvent:code=" + code);
    }

    /**
     * 用户第一帧画面绘制后通知
     */
    @Override
    public void onFirstVideoFrameRendered(String user) {

    }

    /**
     * 用户视频画面分辨率改变通知
     */
    @Override
    public void onVideoFrameResolutionChanged(String user, int width, int height, int rotate) {

    }

    /**
     * 采集视频数据回调
     */
    @Override
    public int onVideoFrameFilter(AVChatVideoFrame avChatVideoFrame) {
        return 0;
    }

    /**
     * 采集语音数据回调
     */
    @Override
    public int onAudioFrameFilter(AVChatAudioFrame avChatAudioFrame) {
        return 0;
    }

    /**
     * 语音播放设备变化通知
     */
    @Override
    public void onAudioOutputDeviceChanged(int device) {

    }

    /**
     * 语音正在说话用户声音强度通知
     */
    @Override
    public void onReportSpeaker(Map<String, Integer> speakers, int mixedEnergy) {

    }

    /**
     * 实时开启互动直播回调通知
     */
    @Override
    public void onStartLiveResult(int i) {

    }

    /**
     * 实时关闭互动直播回调通知
     */
    @Override
    public void onStopLiveResult(int i) {

    }

    /**
     * 伴音事件通知
     * 当伴音出错或者结束时，通过此回调进行通知
     */
    @Override
    public void onAudioMixingEvent(int event) {

    }

    /**
     * 切换大小窗口
     */
    private void switchRender() {
        //先取消用户的画布
        AVChatManager.getInstance().setupVideoRender(selfAccount, null, false, 0);
        AVChatManager.getInstance().setupVideoRender(remoteAccount, null, false, 0);
        //重新设置上画布
        AVChatManager.getInstance().setupVideoRender(selfAccount, selfSurfaceIsLarge ? selfRender : remoteRender, false, AVChatVideoScalingType.SCALE_ASPECT_FILL);
        AVChatManager.getInstance().setupVideoRender(remoteAccount, selfSurfaceIsLarge ? remoteRender : selfRender, false, AVChatVideoScalingType.SCALE_ASPECT_FILL);
        selfSurfaceIsLarge = !selfSurfaceIsLarge;
    }

//    /**
//     * 设置自己视频画布
//     */
//    private Thread selfSurfaceRenderThread = new Thread() {
//        @Override
//        public void run() {
//            selfThreadRunning = true;
//            while (getRender) {//第一次运行会请求摄像头权限，会报空指针
//                try {
//                    AVChatManager.getInstance().setupVideoRender(selfAccount, selfRender, false, AVChatVideoScalingType.SCALE_ASPECT_FILL);
//                } catch (Exception e) {
//                    e.printStackTrace();
//                } finally {
//                    try {
//                        Thread.sleep(2000);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                }
//            }
//            if (getRender) {
//                handler.sendEmptyMessage(RESULT_OK);
//            }
//        }
//    };
//
//    /**
//     * 设置他人视频画布
//     */
//    private Thread remoteSurfaceRenderThread = new Thread() {
//        @Override
//        public void run() {
//            remoteThreadRunning = true;
//            while (getRender) {
//                //第一次运行会请求摄像头权限，会报空指针
//                try {
//                    AVChatManager.getInstance().setupVideoRender(remoteAccount, remoteRender, false, AVChatVideoScalingType.SCALE_ASPECT_FILL);
//                } catch (Exception e) {
//                    e.printStackTrace();
//                } finally {
//                    try {
//                        Thread.sleep(2000);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                }
//            }
//            if (getRender) {
//                handler.sendEmptyMessage(RESULT_OK);
//            }
//        }
//    };

    /**
     * 设置自己视频画布
     */
    private void setCameraSelf() {
        if (selfThreadRunning) {
            return;
        } else {
            selfThreadRunning = true;
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                boolean isFail = true;
                while (isFail) {
                    try {
                        AVChatManager.getInstance().setupVideoRender(selfAccount, selfRender, false, AVChatVideoScalingType.SCALE_ASPECT_FILL);
                        isFail = false;
                    } catch (Exception e) {
                        SystemClock.sleep(1000);
                    }
                }
            }
        }).start();
    }

    /**
     * 设置他人视频画布
     */
    private void setCameraRemote() {
        if (remoteThreadRunning) {
            return;
        } else {
            remoteThreadRunning = true;
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                boolean isFail = true;
                while (isFail) {
                    try {
                        AVChatManager.getInstance().setupVideoRender(remoteAccount, remoteRender, false, AVChatVideoScalingType.SCALE_ASPECT_FILL);
                        isFail = false;
                    } catch (Exception e) {
                        SystemClock.sleep(1000);
                    }
                }
            }
        }).start();
    }

    private void initCamera() {
        SoundPlayer.instance(NimAVChatActivity.this).stop();
        tvChangeMode.setText(getString(R.string.avchat_switch_to_audio));
        tvChangeMode.setCompoundDrawablesWithIntrinsicBounds(R.drawable.avchat_change_to_audio, 0, 0, 0);
        tvChangeMode.setVisibility(View.VISIBLE);
        videoTime.setVisibility(View.VISIBLE);
        largePreview.setVisibility(View.VISIBLE);
        smallPreview.setVisibility(View.VISIBLE);
        llTop.setVisibility(View.GONE);
        llAudioBottom.setVisibility(View.GONE);
        llVideoBottom.setVisibility(View.VISIBLE);
        llBottomButtons.setVisibility(View.GONE);
        if (AVChatManager.getInstance().hasMultipleCameras()) {//是否有多个摄像头
            ibChangeCamera.setEnabled(true);
        }
        ibMuteVideo.setEnabled(true);
        ibMuteAudio.setEnabled(true);
        ibRecord.setEnabled(true);
//        if (!selfThreadRunning) {
//        }
//        if (!remoteThreadRunning) {
//        }
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                setCameraSelf();
                setCameraRemote();
                smallPreview.removeAllViews();
                largePreview.removeAllViews();
                selfRender.setZOrderMediaOverlay(!selfSurfaceIsLarge);
                selfRender.setZOrderOnTop(!selfSurfaceIsLarge);
                remoteRender.setZOrderMediaOverlay(selfSurfaceIsLarge);
                remoteRender.setZOrderOnTop(selfSurfaceIsLarge);
                if (selfSurfaceIsLarge) {//当前用户视频大窗口
                    if (AVChatManager.getInstance().isLocalVideoMuted()) {//摄像头是否关闭
                        tvStatus.setText(getString(R.string.avchat_local_close_camera));
                        tvStatus.setVisibility(View.VISIBLE);
                    } else {
                        largePreview.addView(selfRender);
                        tvStatus.setVisibility(View.GONE);
                    }
                    if (otherCameraOpened) {
                        smallPreview.addView(remoteRender);
                    }
                } else {//当前用户视频小窗口
                    if (!AVChatManager.getInstance().isLocalVideoMuted()) {
                        smallPreview.addView(selfRender);
                    }
                    if (otherCameraOpened) {
                        largePreview.addView(remoteRender);
                        tvStatus.setVisibility(View.GONE);
                    } else {
                        tvStatus.setText(getString(R.string.avchat_peer_close_camera));
                        tvStatus.setVisibility(View.VISIBLE);
                    }
                }
                ibMuteVideo.setSelected(AVChatManager.getInstance().isLocalVideoMuted());
                tvVideoRecording.setVisibility(AVChatManager.getInstance().isLocalRecording() ? View.VISIBLE : View.GONE);
                tvAudioRecording.setVisibility(View.GONE);
                ibRecord.setSelected(AVChatManager.getInstance().isLocalRecording());
            }
        }, 2000);
    }
}
